home *** CD-ROM | disk | FTP | other *** search
/ Openstep 4.2 (Developer) / Openstep Developer 4.2.iso / NextDeveloper / Examples / DriverKit / AMDPCSCSIDriver / AMDPCSCSIDriver_reloc.tproj / AMD_Chip.m < prev    next >
Encoding:
Text File  |  1996-04-03  |  15.8 KB  |  669 lines

  1. /*     Copyright (c) 1994-1996 NeXT Software, Inc.  All rights reserved. 
  2.  *
  3.  * AMD_Chip.m - chip (53C974/79C974) specific methods for AMD SCSI driver
  4.  *
  5.  * HISTORY
  6.  * 21 Oct 94    Doug Mitchell at NeXT
  7.  *      Created. 
  8.  */
  9.  
  10. #import "AMD_Chip.h"
  11. #import "AMD_ChipPrivate.h"
  12. #import "AMD_Private.h"
  13. #import "AMD_x86.h"
  14. #import "AMD_Regs.h"
  15. #import "AMD_Types.h"
  16. #import "AMD_ddm.h"
  17. #import "bringup.h"
  18. #import <driverkit/generalFuncs.h>
  19. #import <kernserv/prototypes.h>
  20.  
  21. IONamedValue scsiMsgValues[] = {
  22.     {MSG_CMDCMPLT,        "Command Complete"    },
  23.     {MSG_EXTENDED,        "Extended Message"    },
  24.     {MSG_SAVEPTRS,        "Save Pointers"        },
  25.     {MSG_RESTOREPTRS,    "Restore Pointers"    },
  26.     {MSG_DISCONNECT,    "Disconnect"        },
  27.     {MSG_IDETERR,        "Initiator Det Error"    },
  28.     {MSG_ABORT,        "Abort"            },
  29.     {MSG_MSGREJECT,        "Message Reject"    },
  30.     {MSG_NOP,        "Nop"            },
  31.     {MSG_MSGPARERR,        "Message parity Error"    },
  32.     {0,            NULL            }
  33. };
  34.  
  35. #ifdef    DDM_DEBUG
  36. IONamedValue scsiPhaseValues[] = {
  37.     {PHASE_DATAOUT,        "data_out"        },
  38.     {PHASE_DATAIN,        "data_in"        },
  39.     {PHASE_COMMAND,        "command"        },
  40.     {PHASE_STATUS,        "status"        },
  41.     {PHASE_MSGOUT,        "message_out"        },
  42.     {PHASE_MSGIN,        "message_in"        },
  43.     {0,            NULL            }
  44. };
  45.  
  46. #endif    DDM_DEBUG
  47.  
  48. #ifdef    DEBUG
  49. /*
  50.  * For IOFindNameForValue() and ddm's.
  51.  */
  52. IONamedValue scStateValues[] = { 
  53.     {SCS_UNINITIALIZED,    "SCS_UNINITIALIZED"    },
  54.         {SCS_DISCONNECTED,    "SCS_DISCONNECTED"    },
  55.         {SCS_SELECTING,        "SCS_SELECTING"        },
  56.         {SCS_INITIATOR,        "SCS_INITIATOR"     },
  57.         {SCS_COMPLETING,    "SCS_COMPLETING"    },
  58.         {SCS_DMAING,        "SCS_DMAING"        },    
  59.         {SCS_ACCEPTINGMSG,    "SCS_ACCEPTINGMSG"    },
  60.         {SCS_SENDINGMSG,    "SCS_SENDINGMSG"    },    
  61.         {SCS_GETTINGMSG,    "SCS_GETTINGMSG"    },    
  62.     {SCS_SENDINGCMD,    "SCS_SENDINGCMD"    },
  63.     {0,             NULL            },
  64. };
  65. #endif    DEBUG
  66.  
  67. @implementation AMD_SCSI(Chip)
  68.  
  69. /*
  70.  * One-time-only init and probe. Returns YES if a functioning chip is 
  71.  * found, else returns NO. -hwReset must be called subsequent to this 
  72.  * to enable operation of the chip.
  73.  */
  74. - (BOOL)probeChip
  75. {
  76.     int target;
  77.     
  78.     /*
  79.      * Init sync mode to async, until we negotiate.
  80.      */
  81.     for(target=0; target<SCSI_NTARGETS; target++) {
  82.         perTarget[target].syncXferOffset = 0;
  83.     }
  84.     return YES;
  85. }
  86.  
  87. /*
  88.  * Reusable 53C974 init function. This includes a SCSI reset.
  89.  * Handling of ioComplete of active and disconnected commands must be done
  90.  * elsewhere. Returns non-zero on error. 
  91.  */
  92. - (int)hwReset : (const char *)reason
  93. {
  94.     int         target;
  95.     unsigned char     reg;
  96.     
  97.     /*
  98.      * First of all, reset interrupts, the SCSI block, and the DMA engine.
  99.      */
  100.     [self disableAllInterrupts];
  101.     WRITE_REG(scsiCmd, SCMD_RESET_DEVICE);
  102.     WRITE_REG(scsiCmd, SCMD_NOP);
  103.     [self dmaIdle];
  104.     
  105.     /*
  106.      * Clear possible pending interrupt.
  107.      */
  108.     READ_REG(intrStatus);
  109.     
  110.     /*
  111.      * Init state variables.
  112.      */
  113.     reselPending  = 0;
  114.     scState       = SCS_DISCONNECTED;
  115.     activeCmd     = NULL;
  116.     currMsgInCnt  = 0;
  117.     currMsgOutCnt = 0;
  118.     msgOutState   = MOS_NONE;
  119.     SDTR_State    = SNS_NONE;
  120.     
  121.     /*
  122.      * Sync negotiation is needed after a reset.
  123.      */
  124.     for(target=0; target<SCSI_NTARGETS; target++) {
  125.         perTarget[target].syncNegotNeeded = 1;
  126.     }
  127.     
  128.     /*
  129.      * Control1....
  130.      */
  131.     reg = CR1_RESET_INTR_DIS | CR1_PERR_ENABLE | AMD_SCSI_ID;
  132.     if(extendTiming) {
  133.         /*
  134.          * Per instance table. This slows down transfers on the
  135.          * bus.
  136.          */
  137.         reg |= CR1_EXTEND_TIMING;
  138.     }
  139.     WRITE_REG(control1, reg);
  140.     ddm_init("control1 = 0x%x\n", reg, 2,3,4,5);
  141.     hostId = AMD_SCSI_ID;
  142.     
  143.     /*
  144.      * Clock factor and select timeout.
  145.      */
  146.     ASSERT(scsiClockRate != 0);
  147.     if(scsiClockRate < 10) {
  148.         IOLog("AMD53C974: Clock %d MHZ too low; using 10 MHz\n",
  149.              scsiClockRate);
  150.         scsiClockRate = 10;
  151.     }
  152.     if(scsiClockRate > 40) {
  153.         IOLog("AMD53C974: Clock %d MHZ too high; using 40 MHz\n",
  154.              scsiClockRate);
  155.         scsiClockRate = 40;
  156.     }
  157.     reg = AMD_CLOCK_FACTOR(scsiClockRate) & 0x7;
  158.     WRITE_REG(clockFactor, reg);
  159.     ddm_init("clockFactor %d\n", reg, 2,3,4,5);
  160.     reg = amdSelectTimeout(AMD_SELECT_TO, scsiClockRate);
  161.     WRITE_REG(scsiTimeout, reg);
  162.     ddm_init("select timeout reg 0x%x\n", reg, 2,3,4,5);
  163.     
  164.     /*
  165.      * control2 - enable extended features - mainly, 24-bit transfer count.
  166.      */
  167.     WRITE_REG(control2, CR2_ENABLE_FEAT);
  168.     
  169.     /*
  170.      * control3
  171.      */
  172.     reg = 0;
  173.     if(fastModeEnable) {
  174.         reg |= CR3_FAST_SCSI;
  175.     }
  176.     if(scsiClockRate > 25) {
  177.         reg |= CR3_FAST_CLOCK;
  178.     }
  179.     ddm_init("control3 = 0x%x\n", reg, 2,3,4,5);
  180.     WRITE_REG(control3, reg);
  181.     
  182.     /*
  183.      * control4 - glitch eater, active negation. Let's not 
  184.      * worry about these whizzy features just yet.
  185.      */
  186.     WRITE_REG(control4, 0);
  187.     
  188.     /*
  189.      * Go to async xfer mode for now. Sync gets enabled on a per-target 
  190.      * basis in -targetContext.
  191.      */
  192.     WRITE_REG(syncOffset, 0);
  193.     
  194.     /*
  195.      * Reset SCSI bus, wait, clear possible interrupt.
  196.      */
  197.     WRITE_REG(scsiCmd, SCMD_RESET_SCSI);
  198.     if(reason) {
  199.         IOLog("AMD53C974: Resetting SCSI bus (%s)\n", reason);
  200.     }
  201.     else {
  202.         IOLog("AMD53C974: Resetting SCSI bus\n");
  203.     }
  204.     IOSleep(AMD_SCSI_RESET_DELAY);
  205.     READ_REG(intrStatus);
  206.  
  207.     ddm_init("hwReset: enabling interrupts\n", 1,2,3,4,5);
  208.     [self enableAllInterrupts];
  209.     
  210.     ddm_init("hwReset: DONE\n", 1,2,3,4,5);
  211.     return 0;    
  212. }
  213.  
  214. /*
  215.  * reset SCSI bus.
  216.  */
  217. - (void)scsiReset
  218. {
  219.     WRITE_REG(scsiCmd, SCMD_RESET_SCSI);
  220.     READ_REG(intrStatus);
  221. }
  222.  
  223. /*
  224.  * Prepare for power down. 
  225.  *  -- reset SCSI bus to get targets back to known state
  226.  *  -- reset chip 
  227.  */
  228. - (void) powerDown
  229. {
  230.     WRITE_REG(scsiCmd, SCMD_RESET_SCSI);
  231.     IODelay(100);                // SCSI spec says 25 us
  232.     READ_REG(intrStatus);            // clear SCSI reset interrupt
  233.     WRITE_REG(scsiCmd, SCMD_RESET_DEVICE);
  234.     IODelay(50);                // chip settle delay
  235.     WRITE_REG(scsiCmd, SCMD_NOP);        // re-enable chip for BIOS
  236. }
  237.  
  238. /*
  239.  * Start a SCSI transaction for the specified command. ActiveCmd must be 
  240.  * NULL. A return of HWS_REJECT indicates that caller may try again
  241.  * with another command; HWS_BUSY indicates a condition other than
  242.  * (activeCmd != NULL) which prevents the processing of the command.
  243.  */
  244. - (hwStartReturn)hwStart : (commandBuf *)cmdBuf
  245. {    
  246.     unsigned char    cdb_ctrl;
  247.     IOSCSIRequest    *scsiReq = cmdBuf->scsiReq;
  248.     cdb_t        *cdbp = &scsiReq->cdb;
  249.     unsigned char    identify_msg = 0;
  250.     unsigned char    *cp;
  251.     unsigned char    okToDisc;
  252.     unsigned char    okToQueue;
  253.     perTargetData    *perTargetPtr;
  254.     int        i;
  255.     BOOL        cmdQueueDisableFlag = NO;
  256.     unsigned char    selectCmd;
  257.     
  258.     ddm_chip("hwStart cmdBuf = 0x%x opcode %s\n", cmdBuf, 
  259.         IOFindNameForValue(cdbp->cdb_opcode, IOSCSIOpcodeStrings),
  260.             3,4,5);
  261.     ASSERT(activeCmd == NULL);
  262.     
  263.     /*
  264.      * Currently, the only reason we return HWS_BUSY is if we have
  265.      * a reselect pending.
  266.      */
  267.     if(reselPending) {
  268.         queue_enter(&pendingQ, cmdBuf, commandBuf *, link);
  269.         return HWS_BUSY;
  270.     }
  271.     ASSERT(scState == SCS_DISCONNECTED);
  272.         
  273.     /*
  274.      * Initialize driver return values and state machine.
  275.      */
  276.     cmdBuf->currentByteCount = cmdBuf->savedByteCount = 
  277.         scsiReq->maxTransfer;
  278.     scsiReq->bytesTransferred = 0;
  279.     cmdBuf->savedPtr = cmdBuf->currentPtr = (vm_offset_t)cmdBuf->buffer;
  280.     scsiReq->driverStatus = SR_IOST_INVALID;
  281.     scsiReq->totalTime  = 0ULL;
  282.     scsiReq->latentTime = 0ULL;
  283.     
  284.     /*
  285.      * Figure out what kind of cdb we've been given and grab the ctrl byte.
  286.      */
  287.     switch (SCSI_OPGROUP(cdbp->cdb_opcode)) {
  288.         case OPGROUP_0:
  289.         cmdBuf->cdbLength = sizeof(cdb_6_t);
  290.         cdb_ctrl  = cdbp->cdb_c6.c6_ctrl;
  291.         break;
  292.         case OPGROUP_1:
  293.         case OPGROUP_2:
  294.         cmdBuf->cdbLength = sizeof(cdb_10_t);
  295.         cdb_ctrl  = cdbp->cdb_c10.c10_ctrl;
  296.         break;
  297.         case OPGROUP_5:
  298.         cmdBuf->cdbLength = sizeof(cdb_12_t);
  299.         cdb_ctrl  = cdbp->cdb_c12.c12_ctrl;
  300.         break;
  301.             case OPGROUP_6:
  302.         cmdBuf->cdbLength = (scsiReq->cdbLength ? 
  303.              scsiReq->cdbLength : sizeof (struct cdb_6));
  304.         cdb_ctrl = 0;
  305.         break;
  306.         case OPGROUP_7:
  307.         cmdBuf->cdbLength = (scsiReq->cdbLength ? 
  308.              scsiReq->cdbLength : sizeof (struct cdb_10));
  309.         cdb_ctrl = 0;
  310.         break;
  311.         default:
  312.         goto abortReq;
  313.     }
  314.     ddm_chip("cdbLength = %d\n", cmdBuf->cdbLength, 2,3,4,5);
  315.     
  316.     /*
  317.      * Do a little command snooping.
  318.      */
  319.     perTargetPtr = &perTarget[scsiReq->target];
  320.     switch(cdbp->cdb_opcode) {
  321.         case C6OP_INQUIRY:
  322.         /*
  323.          * The first command SCSIDisk sends us is an Inquiry command.
  324.          * This never gets retried, so avoid a possible 
  325.          * reject of a command queue tag. Avoid this hack if
  326.          * there are any other commands outstanding for this
  327.          * target/lun.
  328.          */
  329.         if(activeArray[scsiReq->target][scsiReq->lun] == 0) {
  330.             cmdQueueDisableFlag = YES;
  331.         }
  332.         break;
  333.         
  334.         case C6OP_REQSENSE:
  335.             /*
  336.          * Always force sync renegotiation on this one to 
  337.          * catch independent target power cycles.
  338.          */
  339.         if(SYNC_RENEGOT_ON_REQ_SENSE) {
  340.             perTargetPtr->syncNegotNeeded = 1;
  341.         }
  342.         break;
  343.     }
  344.         
  345.     /*
  346.      * Avoid command queueing if if we're going to do sync
  347.      * negotiation.
  348.      * FIXME - this might be illegal - what if we're doing a request 
  349.      * sense in response to a legitimate error, and there are 
  350.      * tagged commands pending?
  351.      */
  352.     if(perTargetPtr->syncNegotNeeded &&
  353.        !perTargetPtr->syncDisable &&
  354.        syncModeEnable) {
  355.            cmdQueueDisableFlag = YES;
  356.         SDTR_State = SNS_HOST_INIT_NEEDED;
  357.         ddm_chip("hwStart: entering SNS_HOST_INIT_NEEDED state\n", 
  358.             1,2,3,4,5);
  359.     }
  360.     else {
  361.         SDTR_State = SNS_NONE;
  362.     }
  363.     
  364.     /*
  365.      * Determine from myriad sources whether or not it's OK to 
  366.      * disconnect and to use command queueing. 
  367.      */
  368.     okToQueue = cmdQueueEnable &&            // global per driver
  369.                 !scsiReq->cmdQueueDisable &&     // per I/O
  370.                 !perTargetPtr->cmdQueueDisable &&      // per target
  371.             !cmdQueueDisableFlag;        // inquiry hack
  372.     okToDisc  = ([self numReserved] >         // > 1 target on bus
  373.             (1 + SCSI_NLUNS)) || 
  374.             okToQueue;                // hope to do cmd q'ing
  375.     #if    FORCE_DISCONNECTS
  376.     okToDisc = 1;
  377.     #else    FORCE_DISCONNECTS
  378.     if(!scsiReq->disconnect) {
  379.         /*
  380.          * This overrides everything...
  381.          */
  382.         okToQueue = okToDisc = 0;
  383.     }
  384.     #endif    FORCE_DISCONNECTS
  385.     cmdBuf->discEnable = okToDisc;
  386.     if(okToQueue) {
  387.         /*
  388.          * Avoid using tag QUEUE_TAG_NONTAGGED...
  389.          */
  390.         cmdBuf->queueTag = nextQueueTag;
  391.         if(++nextQueueTag == QUEUE_TAG_NONTAGGED) {
  392.             nextQueueTag++;
  393.         }
  394.     }
  395.     else {
  396.         cmdBuf->queueTag = QUEUE_TAG_NONTAGGED;
  397.     }
  398.     
  399.     /*
  400.      * Make sure nothing unreasonable has been asked of us. 
  401.      */
  402.     if((cdb_ctrl & CTRL_LINKFLAG) != CTRL_NOLINK) {
  403.         ddm_err("Linked CDB (Unimplemented)\n",
  404.             1,2,3,4,5);
  405.         goto abortReq;
  406.     }
  407.  
  408.     /*
  409.      * OK, this command is hot.
  410.      */
  411.     [self activateCommand:cmdBuf];
  412.     
  413.     scState = SCS_SELECTING;
  414.     msgOutState = MOS_NONE;
  415.     bzero(currMsgIn, AMD_MSG_SIZE);
  416.     bzero(currMsgOut, AMD_MSG_SIZE);
  417.     currMsgInCnt = 0;
  418.     currMsgOutCnt = 0;
  419.     
  420.     /*
  421.      * Load per-target context.
  422.      */
  423.     [self targetContext:scsiReq->target];
  424.  
  425.     /*
  426.      * set target bus id
  427.      * punch message(s), optional cdb into fifo
  428.      * write appropriate select command
  429.      */
  430.     ddm_chip("hwStart: opcode 0x%x targ %d lun %d maxTransfer 0x%x\n", 
  431.          cdbp->cdb_opcode, scsiReq->target, scsiReq->lun, 
  432.          scsiReq->maxTransfer, 5);
  433.     WRITE_REG(scsiCmd, SCMD_CLEAR_FIFO);
  434.     WRITE_REG(scsiDestID, scsiReq->target);
  435.     identify_msg = MSG_IDENTIFYMASK | (scsiReq->lun & MSG_ID_LUNMASK);
  436.     if(okToDisc) {
  437.         identify_msg |= MSG_ID_DISCONN;
  438.     }
  439.  
  440.     WRITE_REG(scsiFifo, identify_msg);
  441.     
  442.     /*
  443.      * Note this logic assumes that queue tag and SDTR messages are
  444.      * mutually exclusive...
  445.      */
  446.     if(SDTR_State == SNS_HOST_INIT_NEEDED) {
  447.         selectCmd = SCMD_SELECT_ATN_STOP;
  448.     }
  449.     else {
  450.         if(okToQueue) {
  451.             WRITE_REG(scsiFifo, MSG_SIMPLE_QUEUE_TAG);
  452.             WRITE_REG(scsiFifo, cmdBuf->queueTag);
  453.             
  454.             /*
  455.              * Save these in currMsgOut[] in case 
  456.              * the target rejects this message.
  457.              */
  458.             currMsgOut[0] = MSG_SIMPLE_QUEUE_TAG;
  459.             currMsgOut[1] = cmdBuf->queueTag;
  460.             currMsgOutCnt = 2;
  461.         }
  462.         cp = (u_char *)cdbp;
  463.         for(i=0; i<cmdBuf->cdbLength; i++) {
  464.             WRITE_REG(scsiFifo, *cp++);
  465.         }
  466.         if(okToQueue) {
  467.             selectCmd = SCMD_SELECT_ATN_3;
  468.         }
  469.         else {
  470.             selectCmd = SCMD_SELECT_ATN;
  471.         }
  472.     }
  473.     WRITE_REG(scsiCmd, selectCmd);
  474.     IOGetTimestamp(&cmdBuf->startTime);
  475.     return HWS_OK;
  476.     
  477. abortReq:
  478.     scsiReq->driverStatus = SR_IOST_CMDREJ;
  479.     [self ioComplete:cmdBuf];
  480.     return HWS_REJECT;
  481. }
  482.  
  483. /*
  484.  * SCSI device interrupt handler.
  485.  */
  486. - (void)hwInterrupt
  487. {
  488.     ddm_chip("hwInterrupt: activeCmd 0x%x\n", activeCmd, 2,3,4,5);
  489.     
  490.     switch([self scsiInterruptPending]) {
  491.         case SINT_NONE:
  492.         /*
  493.          * Must be another device....
  494.          */
  495.         [self enableAllInterrupts];
  496.         return;
  497.         case SINT_DEVICE:
  498.         case SINT_DMA:
  499.             break;
  500.         default:
  501.             /* 
  502.          * What do we do now, batman?
  503.          */
  504.         [self hwAbort:SR_IOST_HW reason:"Bad Interrupt Received"];
  505.         return;
  506.     }
  507.     
  508. goAgain:
  509.     /*
  510.      * Save interrupt state.
  511.      */
  512.     saveStatus     = READ_REG(scsiStat);
  513.     saveSeqStep    = READ_REG(internState);
  514.     saveIntrStatus = READ_REG(intrStatus);
  515.         
  516.     ddm_chip("   status 0x%x intstatus 0x%x scState %s\n", 
  517.         saveStatus, saveIntrStatus, 
  518.         IOFindNameForValue(scState, scStateValues), 4,5);
  519.     if((saveStatus & SS_ILLEGALOP) || (saveIntrStatus & IS_ILLEGALCMD)) {
  520.        
  521.          /*
  522.          * Software screwup. Start over from scratch.
  523.          */
  524.         IOLog("AMD53C974: hardware command reject\n");
  525.         [self hwAbort:SR_IOST_INT reason:"Hardware Command Reject"];
  526.         return;
  527.     }
  528.  
  529.     /*
  530.      * OK, grind thru the state machine.
  531.      */
  532.     switch(scState) {
  533.            case SCS_DISCONNECTED:
  534.            [self fsmDisconnected];
  535.         break;
  536.            case SCS_SELECTING:
  537.            [self fsmSelecting];
  538.         break;
  539.            case SCS_INITIATOR:
  540.            [self fsmInitiator];
  541.         break;
  542.            case SCS_COMPLETING:
  543.            [self fsmCompleting];
  544.         break;
  545.            case SCS_DMAING:
  546.            [self fsmDMAing];
  547.         break;
  548.            case SCS_ACCEPTINGMSG:
  549.            [self fsmAcceptingMsg];
  550.         break;
  551.            case SCS_SENDINGMSG:
  552.            [self fsmSendingMsg];
  553.         break;
  554.            case SCS_GETTINGMSG:
  555.            [self fsmGettingMsg];
  556.         break;
  557.        case SCS_SENDINGCMD:
  558.            [self fsmSendingCmd];
  559.         break;
  560.        default:
  561.            IOPanic("AMD53C974: Bad scState");
  562.     } /* switch scState */
  563.     
  564.     if ((scState != SCS_DISCONNECTED) &&
  565.         (saveIntrStatus & IS_DISCONNECT)) {
  566.         /*
  567.          * the target just up and went away. This is a catch-all
  568.          * trap for any unexpected disconnect.
  569.          */
  570.         ddm_err("hwInterrupt: target disconnected\n", 1,2,3,4,5);
  571.         scState = SCS_DISCONNECTED;
  572.         if(activeCmd != NULL) {
  573.             activeCmd->scsiReq->driverStatus = SR_IOST_TABT;
  574.             [self ioComplete:activeCmd];
  575.             activeCmd = NULL;
  576.         }
  577.     }
  578.     
  579.     /*
  580.      * Handle a SCSI Phase change if necessary.
  581.      */
  582.     if (scState == SCS_INITIATOR)
  583.         [self fsmPhaseChange];
  584. #ifdef    DEBUG
  585.     else {
  586.         ddm_chip("hwInterrupt #2: scState %s\n", 
  587.             IOFindNameForValue(scState, scStateValues),
  588.             2,3,4,5);
  589.     }
  590. #endif    DEBUG
  591.  
  592.     /*
  593.      * If we're off the bus, enable reselection at chip level.
  594.      */
  595.     if (scState == SCS_DISCONNECTED) {
  596.         ddm_chip("hwInterrupt: enabling reselection\n", 1,2,3,4,5);
  597.         WRITE_REG(scsiCmd, SCMD_ENABLE_SELECT);
  598.     }
  599.     
  600.     
  601.     /*
  602.      * If another SCSI interrupt is pending, go for it again (avoiding 
  603.      * an unnecessary enableInterrupt and msg_receive()).
  604.      */
  605.     switch([self scsiInterruptPending]) {
  606.         case SINT_DEVICE:
  607.             #if    INTR_LATENCY_TEST
  608.         ddm_chip("hwInterrupt: INTR TRUE; EXITING FOR MEASUREMENT\n",
  609.             1,2,3,4,5);
  610.         break;
  611.         #else    INTR_LATENCY_TEST
  612.             ddm_chip("hwInterrupt: going again without enabling "
  613.             "interrupt\n", 1,2,3,4,5);
  614.             goto goAgain;
  615.         #endif    INTR_LATENCY_TEST
  616.         default:
  617.             break;
  618.     }
  619.  
  620.     [self enableAllInterrupts];
  621.     
  622.     /*
  623.      * One more thing - if we're still disconnected, enable processing
  624.      * of new commands. 
  625.      */
  626.     if(scState == SCS_DISCONNECTED)
  627.         [self busFree];
  628.     ddm_chip("hwInterrupt: DONE; scState %s\n", 
  629.         IOFindNameForValue(scState, scStateValues), 2,3,4,5);
  630. }
  631.  
  632.  
  633. - (void)logRegs
  634. {
  635. #if    DEBUG
  636.     unsigned char     cs, cis;
  637.     unsigned char     fifoDepth;
  638.     unsigned    scsiXfrCnt;
  639.     unsigned    value;
  640.     
  641.     IOLog("*** saveStatus 0x%x saveIntrStatus 0x%x\n", 
  642.         saveStatus, saveIntrStatus);
  643.     IOLog("*** scState = %s  scsiCmd = 0x%x\n", 
  644.         IOFindNameForValue(scState, scStateValues),
  645.         READ_REG(scsiCmd));
  646.         
  647.     cs = READ_REG(scsiStat);
  648.     cis = READ_REG(intrStatus);
  649.     IOLog("*** current status 0x%x current intrStatus 0x%x\n", cs, cis);
  650.     
  651.     IOLog("*** syncOffset %d  syncPeriod 0x%x\n", 
  652.         syncOffsetShadow, syncPeriodShadow);
  653.     
  654.     fifoDepth = READ_REG(currFifoState) & FS_FIFO_LEVEL_MASK;
  655.     scsiXfrCnt = READ_REG(currXfrCntLow);
  656.     value = READ_REG(currXfrCntMid);
  657.     scsiXfrCnt += (value << 8);
  658.     value = READ_REG(currXfrCntHi);
  659.     scsiXfrCnt += (value << 16);
  660.     IOLog("*** fifoDepth %d  scsiXfrCnt 0x%x\n", fifoDepth, scsiXfrCnt);
  661. #endif    DEBUG
  662. }
  663.  
  664.  
  665. @end    /* AMD_SCSI(Chip) */
  666.  
  667. /* end of AMD_Chip.m */
  668.  
  669.